package com.jm.product.controller.core;

import java.beans.PropertyEditorSupport;
import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.validation.ConstraintViolationException;
import javax.validation.Validator;

import org.apache.commons.lang3.StringEscapeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.ui.Model;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.java.framework.common.beanvalidator.BeanValidators;
import com.java.framework.common.pagination.OrderBy;
import com.java.framework.common.pagination.Pager;
import com.java.framework.common.pagination.SearchBean;
import com.java.framework.common.utils.DateUtils;
import com.java.framework.common.utils.Reflections;
import com.java.framework.common.utils.RequestUtils;
import com.java.framework.service.BaseService;
import com.jm.product.entity.IdEntity;
import com.jm.product.utils.UploadFileUtils;

/**
 * 控制器支持类
 * 
 * @author sunshine
 * @version 2013-3-23
 */
public abstract class BaseController<T extends IdEntity<PK>, PK extends Serializable>{ //extends com.cj.framework.mvc.web.BaseController{

	protected final static Logger log= LoggerFactory.getLogger(BaseController.class);
	
	protected static final String SUCCESS = "success" ;
	protected static final String MESSAGE = "message" ;
	protected HttpServletRequest request;  
    protected HttpServletResponse response;  
    protected HttpSession session;
   
    // 具体的数据对象
 	protected T data;
    private Class<T> clazz;
 	//数据集合
 	protected List<T> datas;
 	
 	@Value("${application.file.upload.path}")
 	protected String uploadPath;

	/**
	 * 验证Bean实例对象
	 */
	@Autowired
	protected Validator validator;
	
	/**
	 * service
	 */
	@Autowired
	protected BaseService<T, PK> service ;

	public BaseController(){
		clazz = Reflections.getClassGenricType(getClass()) ;
	}
	
	@ModelAttribute
	public T get(@RequestParam(required=false) PK id) throws Exception {
		if (null != id){
			if(this.service == null)
				throw new Exception("service must be set") ;
			this.data = service.getById(id);
		}else{
			Class<T> clazz = Reflections.getClassGenricType(getClass()) ;
			this.data = clazz.newInstance() ;
		}
		return this.data ;
	}

	@ModelAttribute
    protected void setReqAndRes(HttpServletRequest request, HttpServletResponse response){  
        this.request = request;
        this.response = response;
        this.session = request.getSession();
    }

	protected HttpSession getSession() {
		return session;
	}

	protected HttpServletRequest getRequest() {
		return request;
	}

	protected HttpServletResponse getResponse() {
		return response;
	}

	protected abstract String listPage();

	@RequestMapping(value = {"list", ""})
	public String list(T data, HttpServletRequest request, HttpServletResponse response, Model model) {
		Map<String, Object> searchParams = new HashMap<String, Object>();
		Pager<T> pager = RequestUtils.getPager(request);
		List<SearchBean> searchBeanList = RequestUtils.populateSBs(
				searchParams, request, clazz);
		List<OrderBy> orderBies = Lists.newArrayList();
		//TODO: 在这里加入默认排序字段
//		orderBies.add(new OrderBy("", OrderBy.OrderByDirection.ASC));
		pager = service.getPager(searchBeanList, orderBies, pager.getCurrentPage(), pager.getPageSize()) ;
		model.addAttribute("page", pager);
		model.addAllAttributes(searchParams);
		return listPage();
	}

	@RequestMapping(value = "form")
	protected abstract String form(T data, Model model);

	protected abstract String savePage();

	@RequestMapping(value = "save")
	public String save(T data, Model model, RedirectAttributes redirectAttributes, HttpServletRequest request) {
		if (!beanValidator(model, data)){
			return form(data, model);
		}
		service.save(data);
		addMessage(redirectAttributes, "保存成功");
		return savePage();
	}

	@RequestMapping(value = "delete")
	@ResponseBody
	public Map<String, Object> delete(@RequestParam PK id, RedirectAttributes redirectAttributes) {
		Map<String, Object> returnMap = Maps.newHashMap() ;
		try {
			this.service.removeById(id);
			returnMap.put(SUCCESS, true);
			returnMap.put(MESSAGE, "删除成功") ;
		} catch (Exception e) {
			returnMap.put(SUCCESS, false);
			returnMap.put(MESSAGE, "删除失败") ;
			e.printStackTrace();
		}
		return returnMap;
	}
	
	protected String getUploadRootPath() {
		 return session.getServletContext().getRealPath("/") ;
	}
	
	@RequestMapping("upload")
	@ResponseBody
	public Map<String,Object> upload(@RequestParam(required=true)String subFolder, HttpServletRequest request) {
		Map<String,Object> map = Maps.newHashMap();
		if(request instanceof MultipartHttpServletRequest){
			// 对文件进处理
            MultipartHttpServletRequest multipartHttpServletRequest = (MultipartHttpServletRequest) request;
            String uploadFolder = this.uploadPath + "/" + subFolder ;
            // 获取上传的文件
            Map<String, MultipartFile> fileMap = multipartHttpServletRequest.getFileMap();
            for(Map.Entry<String, MultipartFile> entry : fileMap.entrySet()){
                try {
                	//TODO:这里可改为云存储，目前暂存储在项目目录下
                	String filePath = UploadFileUtils.upload(entry.getValue(), getUploadRootPath(), uploadFolder);
                	log.info("成功上传文件：" + filePath);
                	map.put(MESSAGE, filePath);
                	map.put(SUCCESS, true);
				} catch (Exception e) {
					map.put(MESSAGE, "上传失败："+e.getMessage());
                	map.put(SUCCESS, false);
					e.printStackTrace();
				}
            }
		} else {
			map.put(MESSAGE, "非文件上传!");
        	map.put(SUCCESS, false);
		}
		return map;
	}
  
	/**
	 * 服务端参数有效性验证
	 * 
	 * @param object
	 *            验证的实体对象
	 * @param groups
	 *            验证组
	 * @return 验证成功：返回true；验证失败：将错误信息添加到 message 中
	 */
	protected boolean beanValidator(Model model, Object object, Class<?>... groups) {
		try {
			BeanValidators.validateWithException(validator, object, groups);
		} catch (ConstraintViolationException ex) {
			List<String> list = BeanValidators.extractPropertyAndMessageAsList(ex, ": ");
			list.add(0, "数据验证失败：");
			addMessage(model, list.toArray(new String[] {}));
			return false;
		}
		return true;
	}

	/**
	 * 服务端参数有效性验证
	 * 
	 * @param object
	 *            验证的实体对象
	 * @param groups
	 *            验证组
	 * @return 验证成功：返回true；验证失败：将错误信息添加到 flash message 中
	 */
	protected boolean beanValidator(RedirectAttributes redirectAttributes,
			Object object, Class<?>... groups) {
		try {
			BeanValidators.validateWithException(validator, object, groups);
		} catch (ConstraintViolationException ex) {
			List<String> list = BeanValidators.extractPropertyAndMessageAsList(ex, ": ");
			list.add(0, "数据验证失败：");
			addMessage(redirectAttributes, list.toArray(new String[] {}));
			return false;
		}
		return true;
	}

	/**
	 * 添加Model消息
	 * 
	 * @param messages
	 *            消息
	 */
	protected void addMessage(Model model, String... messages) {
		StringBuilder sb = new StringBuilder();
		for (String message : messages) {
			sb.append(message).append(messages.length > 1 ? "<br/>" : "");
		}
		model.addAttribute(MESSAGE, sb.toString());
	}

	/**
	 * 添加Flash消息
	 * 
	 * @param messages
	 *            消息
	 */
	protected void addMessage(RedirectAttributes redirectAttributes,
			String... messages) {
		StringBuilder sb = new StringBuilder();
		for (String message : messages) {
			sb.append(message).append(messages.length > 1 ? "<br/>" : "");
		}
		redirectAttributes.addFlashAttribute(MESSAGE, sb.toString());
	}

	/**
	 * 初始化数据绑定 
	 * 1. 将所有传递进来的String进行HTML编码，防止XSS攻击 
	 * 2. 将字段中Date类型进行转换
	 */
	@InitBinder
	protected void initBinder(WebDataBinder binder) {
		// String类型转换，将所有传递进来的String进行HTML编码，防止XSS攻击
		binder.registerCustomEditor(String.class, new PropertyEditorSupport() {
			@Override
			public void setAsText(String text) {
				setValue(text == null ? null : StringEscapeUtils.escapeHtml4(text.trim()));
			}

			@Override
			public String getAsText() {
				Object value = getValue();
				return value != null ? value.toString() : "";
			}
		});
		// Date 类型转换
		binder.registerCustomEditor(Date.class, new PropertyEditorSupport() {
			@Override
			public void setAsText(String text) {
				setValue(DateUtils.parseDate(text));
			}
		});
	}
	
}

